package com.cicadasmall.system.service.impl;

import com.cicadasmall.common.base.BaseService;
import com.cicadasmall.common.enums.JobStatus;
import com.cicadasmall.common.resp.R;
import com.cicadasmall.system.dto.QuartzJobInputDTO;
import com.cicadasmall.system.dto.QuartzJobQueryDTO;
import com.cicadasmall.system.dto.QuartzJobUpdateDTO;
import com.cicadasmall.data.domain.QuartzJobDO;
import com.cicadasmall.data.mapper.SysQuartzJobMapper;
import com.cicadasmall.system.service.IQuartzJobService;
import org.quartz.*;
import org.redisson.executor.CronExpression;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;

/**
 * <p>
 * 定时任务 服务实现类
 * </p>
 *
 * @author jin
 * @since 2020-04-29
 */
@Service
public class QuartzJobServiceImpl extends BaseService<SysQuartzJobMapper, QuartzJobDO> implements IQuartzJobService {
    @Autowired
    private Scheduler scheduler;

    private static final String TRIGGER_IDENTITY = "trigger_";

    @Override
    public R page(QuartzJobQueryDTO quartzJobQueryDTO) {
        QuartzJobDO quartzJob = quartzJobQueryDTO.convertToEntity();
        return R.ok(baseMapper.selectPage(quartzJobQueryDTO.page(), getLambdaQueryWrapper().setEntity(quartzJob)));
    }

    @Transactional
    @Override
    public R save(QuartzJobInputDTO quartzJobInputDTO) throws Exception {
        QuartzJobDO quartzJob = quartzJobInputDTO.convertToEntity();

        schedulerJob(quartzJob);

        quartzJob.setTriggerState(JobStatus.ACQUIRED.getStatus());
        quartzJob.setOldJobGroup(quartzJob.getJobGroup());
        quartzJob.setOldJobName(quartzJob.getJobName());

        baseMapper.insert(quartzJob);

        return R.ok(true);
    }

    @Transactional
    @Override
    public R update(QuartzJobUpdateDTO quartzJobUpdateDTO) throws Exception {
        QuartzJobDO quartzJob = quartzJobUpdateDTO.convertToEntity();

        scheduler.deleteJob(new JobKey(quartzJob.getOldJobName(), quartzJob.getOldJobGroup()));

        schedulerJob(quartzJob);

        quartzJob.setOldJobGroup(quartzJob.getJobGroup());
        quartzJob.setOldJobName(quartzJob.getJobName());

        baseMapper.updateById(quartzJob);

        return R.ok(true);
    }

    @Override
    public R findById(Serializable id) {
        QuartzJobDO quartzJob = baseMapper.selectById(id);
        return R.ok(quartzJob);
    }

    @Override
    public R deleteById(Serializable id) throws Exception {
        QuartzJobDO quartzJob = getById(id);
        TriggerKey triggerKey = TriggerKey.triggerKey(TRIGGER_IDENTITY + quartzJob.getJobName(), quartzJob.getJobGroup());
        scheduler.pauseTrigger(triggerKey);// 停止触发器
        scheduler.unscheduleJob(triggerKey);// 移除触发器
        scheduler.deleteJob(JobKey.jobKey(quartzJob.getJobName(), quartzJob.getJobGroup()));// 删除任务

        removeById(id);

        return R.ok(true);
    }

    @Override
    public R triggerJob(Serializable id) throws Exception {

        QuartzJobDO quartzJob = getById(id);
        scheduler.triggerJob(JobKey.jobKey(quartzJob.getJobName(), quartzJob.getJobGroup()));

        return R.ok(true);
    }

    @Override
    public R pauseJob(Serializable id) throws Exception {
        QuartzJobDO quartzJob = getById(id);

        scheduler.pauseJob(JobKey.jobKey(quartzJob.getJobName(), quartzJob.getJobGroup()));

        quartzJob.setTriggerState(JobStatus.PAUSED.getStatus());

        updateById(quartzJob);

        return R.ok(true);
    }

    @Override
    public R resumeJob(Serializable id) throws Exception {
        QuartzJobDO quartzJob = getById(id);
        scheduler.resumeJob(JobKey.jobKey(quartzJob.getJobName(), quartzJob.getJobGroup()));
        quartzJob.setTriggerState(JobStatus.RUNNING.getStatus());
        updateById(quartzJob);
        return R.ok(true);
    }


    @Override
    public void schedulerJob(QuartzJobDO job) throws Exception {
        if (!CronExpression.isValidExpression(job.getCronExpression())) {
            throw new IllegalArgumentException("cron 表达式不正确！");
        }

        if (scheduler.checkExists(JobKey.jobKey(job.getJobName(), job.getJobGroup())) ||
                scheduler.checkExists(TriggerKey.triggerKey(TRIGGER_IDENTITY + job.getJobName(), job.getJobGroup()))) {
            return;
        }

        scheduler.scheduleJob(
                JobBuilder
                        .newJob((Class<? extends Job>) Class.forName(job.getJobClassName()))
                        .withIdentity(job.getJobName(), job.getJobGroup()).withDescription(job
                        .getDescription())
                        .build()
                , TriggerBuilder
                        .newTrigger()
                        .withIdentity(TRIGGER_IDENTITY + job.getJobName(), job.getJobGroup())
                        .startNow()
                        .withSchedule(CronScheduleBuilder.cronSchedule(job.getCronExpression().trim())).build());
    }

}
